﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EPiServer.Web.Hosting;
using System.Collections.Specialized;
using Microsoft.WindowsAzure;
using System.Web;
using DBLOG.Azure.VirtualPathProvider.Entities;
using System.Configuration;
using System.Web.Hosting;
using System.IO;
using log4net;
using System.Diagnostics;

namespace DBLOG.Azure.VirtualPathProvider
{
    /// <summary>
    /// Virtual Path Provider for Windows Azure storage
    /// </summary>
    class BlobStorageProvider : VirtualPathUnifiedProvider
    {
        #region properties

        private static readonly ILog _log = LogManager.GetLogger(typeof(BlobStorageProvider));

        /// <summary>
        /// Gets or sets the container name for blob storage
        /// </summary>
        private string _BlobStorageContainerName { get; set; }

        /// <summary>
        /// Gets or sets the folder root name
        /// </summary>
        private string _RootPath { get; set; }

        /// <summary>
        /// Gets or sets the custom file summary configuration file
        /// </summary>
        /// <remarks>Defaults to FileSummary.config</remarks>
        private string _CustomSummary { get; set; }

        /// <summary>
        /// Gets or sets the root directory in the blob storage container
        /// </summary>
        private CloudDirectory _CloudRootDirectory { get; set; }

        #endregion

        public BlobStorageProvider(string name, NameValueCollection configurationParameters)
            : base(name, configurationParameters)
        {
            base.ValidateAndSetupConfigParams();

            SetCustomConfigParams(configurationParameters);

            // Validate custom configuration parameters
            ValidateCustomConfigParams();

            this.VirtualPathRoot = _RootPath;

            // Set the root directory using the root path
            // TODO: do not bypass access check
            _CloudRootDirectory = new CloudDirectory(this, _RootPath, _CustomSummary, true, this._BlobStorageContainerName);
        }

        public override bool DirectoryExists(string virtualDir)
        {
            if (virtualDir.StartsWith(_RootPath))
            {
                if (_RootPath.Equals(virtualDir))
                {
                    return true;
                }

                // If the blob is NOT NULL then it exists
                return BlobStorageDataFactory.Instance.GetDirectory(virtualDir, this._BlobStorageContainerName) != null;
            }
            else
            {
                return Previous.DirectoryExists(virtualDir);
            }
        }

        public override bool FileExists(string virtualPath)
        {
            Trace.WriteLine("FileExists: " + virtualPath);

            if (String.IsNullOrEmpty(virtualPath))
            {
                return false;
            }

            if (virtualPath.EndsWith("/"))
            {
                return false;
            }           

            if (virtualPath.StartsWith(this._RootPath, StringComparison.InvariantCultureIgnoreCase))
            {
                // If the blob is NOT NULL then it exists
                return BlobStorageDataFactory.Instance.GetFile(virtualPath, this._BlobStorageContainerName) != null;
            }

            return base.Previous.FileExists(virtualPath);
        }

        public override VirtualFile GetFile(string virtualPath)
        {
            if (virtualPath.StartsWith(_RootPath, StringComparison.InvariantCultureIgnoreCase))
            {
                return FindFile(virtualPath);
            }

            return Previous.GetFile(virtualPath);
        }

        private VirtualFile FindFile(string virtualPath)
        {
            if (BlobStorageDataFactory.Instance.GetFile(virtualPath, this._BlobStorageContainerName) == null)
            {
                return null;
            }

            string directoryPath = VirtualPathUtility.GetDirectory(virtualPath);

            CloudDirectory directory = new CloudDirectory(this, directoryPath, String.Empty, true, this._BlobStorageContainerName);

            CloudFile file = new CloudFile(directory, this, virtualPath, true, this._BlobStorageContainerName);
            
            return file;
        }

        public override VirtualDirectory GetDirectory(string virtualDir)
        {
            Trace.WriteLine("GetDirectory: " + virtualDir);

            if (virtualDir.Equals(_RootPath, StringComparison.InvariantCultureIgnoreCase))
            {
                return _CloudRootDirectory;
            }
            else if (virtualDir.StartsWith(_RootPath, StringComparison.InvariantCultureIgnoreCase))
            {
                if (BlobStorageDataFactory.Instance.GetDirectory(virtualDir, this._BlobStorageContainerName) != null)
                {
                    return new CloudDirectory(this, virtualDir, _CustomSummary, true, this._BlobStorageContainerName);
                }

            }

            return this.Previous.GetDirectory(virtualDir);
        }

        /// <summary>
        /// Set custom configuration parameters
        /// </summary>
        private void SetCustomConfigParams(NameValueCollection configurationParameters)
        {
            _BlobStorageContainerName = configurationParameters["blobStorageContainer"] as string;

            _RootPath = configurationParameters["virtualPath"] as string;

            _CustomSummary = configurationParameters["customSummary"] as string ?? "/FileSummary.config";

            if (!String.IsNullOrEmpty(_RootPath))
            {
                _RootPath = VirtualPathUtility.AppendTrailingSlash(VirtualPathUtility.ToAbsolute(_RootPath));
            }
        }

        /// <summary>
        /// Validate custom configuration parameters
        /// </summary>
        private void ValidateCustomConfigParams()
        {
            if (String.IsNullOrEmpty(_BlobStorageContainerName))
            {
                throw new BlobStorageProviderException("BlobStorageContainer cannot be empty or missing. Please set the blobStorageContainer attribute.");
            }

            if (String.IsNullOrEmpty(_RootPath))
            {
                throw new BlobStorageProviderException("Virtual path cannot be empty or missing. Please set the virtualPath attribute.");
            }
        }
    }
}
